<?php

namespace App\Exceptions;

use Illuminate\Auth\Access\AuthorizationException;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
use Illuminate\Http\Exceptions\HttpResponseException;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\Log;
use Illuminate\Validation\ValidationException;
use PDOException;
use Symfony\Component\HttpKernel\Exception\HttpException;
use Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Throwable;

class Handler extends ExceptionHandler
{
  /**
   * A list of the exception types that are not reported.
   *
   * @var array
   */
  protected $dontReport = [
    AuthorizationException::class,
    HttpException::class,
    ModelNotFoundException::class,
    ValidationException::class,
    PDOException::class,
  ];

  /**
   * A list of the inputs that are never flashed for validation exceptions.
   *
   * @var array
   */
  protected $dontFlash = [
    'password',
    'password_confirmation',
  ];

  /**
   * Report or log an exception.
   *
   * @throws \Exception
   */
  public function report(Throwable $exception)
  {
    parent::report($exception);
  }

  /**
   * Render an exception into an HTTP response.
   *
   * @param \Illuminate\Http\Request $request
   *
   * @throws \Throwable
   *
   * @return \Symfony\Component\HttpFoundation\Response
   */
  public function render($request, Throwable $exception)
  {

    if ($exception instanceof ValidationException) {
      return parent::render($request, $exception);
    }

    $status = Response::HTTP_INTERNAL_SERVER_ERROR;

    if ($exception instanceof HttpResponseException) {
      $status = Response::HTTP_INTERNAL_SERVER_ERROR;
      Log::info($exception->getMessage());
    } elseif ($exception instanceof MethodNotAllowedHttpException) {
      $status = Response::HTTP_METHOD_NOT_ALLOWED;
      Log::info($exception->getMessage());
      $exception = new MethodNotAllowedHttpException([], 'HTTP_METHOD_NOT_ALLOWED', $exception);
    } elseif ($exception instanceof NotFoundHttpException || $exception instanceof ModelNotFoundException) {
      $status = Response::HTTP_NOT_FOUND;
      Log::info($exception->getMessage());
      $exception = new NotFoundHttpException('HTTP_NOT_FOUND', $exception);
    } elseif ($exception instanceof AuthorizationException) {
      $status = Response::HTTP_FORBIDDEN;
      Log::info($exception->getMessage());
      $exception = new AuthorizationException('HTTP_FORBIDDEN', $status);
    } elseif ($exception instanceof PDOException || 23503 == $exception->getCode()) {
      $status = Response::HTTP_FORBIDDEN;
      Log::info($exception->getMessage());
      $exception = new PDOException('Foreign key violation', $status);
    } elseif ($exception) {
      $exception = new HttpException($status, 'HTTP_INTERNAL_SERVER_ERROR');
    }

    return response()->json([
      'success' => false,
      'status' => $status,
      'message' => $exception->getMessage(),
    ], $status);
  }
}
